/*
   SeeedOLED.h
   SSD130x OLED Driver Library

   Copyright (c) 2011 seeed technology inc.
   Author        :   Visweswara R
   Create Time   :   Dec 2011
   Change Log    :

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
/* adapted for kianRiscV 2021 by Hirosh Dabui */


#include "kianv_i2c_bitbang.h"

#define SeeedOLED_Max_X                 127 //128 Pixels
#define SeeedOLED_Max_Y                 63  //64  Pixels

#define PAGE_MODE                       01
#define HORIZONTAL_MODE                 02


#define SeeedOLED_Address               0x3c
#define SeeedOLED_Command_Mode          0x80
#define SeeedOLED_Data_Mode             0x40
#define SeeedOLED_Display_Off_Cmd       0xAE
#define SeeedOLED_Display_On_Cmd        0xAF
#define SeeedOLED_Normal_Display_Cmd    0xA6
#define SeeedOLED_Inverse_Display_Cmd   0xA7
#define SeeedOLED_Activate_Scroll_Cmd   0x2F
#define SeeedOLED_Dectivate_Scroll_Cmd  0x2E
#define SeeedOLED_Set_Brightness_Cmd    0x81

#define Scroll_Left             0x00
#define Scroll_Right            0x01

#define Scroll_2Frames          0x7
#define Scroll_3Frames          0x4
#define Scroll_4Frames          0x5
#define Scroll_5Frames          0x0
#define Scroll_25Frames         0x6
#define Scroll_64Frames         0x1
#define Scroll_128Frames        0x2
#define Scroll_256Frames        0x3

#define delay(s) msleep(s)
static const unsigned char SeeedLogo[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x60, 0xf0, 0xc0, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
  0xff, 0xfc, 0x00, 0x00, 0x00, 0x80, 0xf0, 0x20, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0x60, 0xe0, 0xc0,
  0xc0, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x60, 0xe0, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x80, 0xc0,
  0xc0, 0xe0, 0x60, 0xc0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x60, 0xe0, 0xc0, 0xc0,
  0x80, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00,
  0x00, 0xc0, 0xc0, 0xe0, 0x60, 0xc0, 0xc0, 0x80, 0x00, 0xc0, 0xf0, 0xf0, 0xf0, 0xc0, 0x00, 0xc0,
  0xc0, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xc0, 0xc0,
  0xf8, 0xf8, 0x00, 0xd8, 0xd8, 0x00, 0x00, 0x80, 0xc0, 0xc0, 0xe0, 0x60, 0xc0, 0xc0, 0x80, 0x00,
  0x00, 0x03, 0x0f, 0x1e, 0x3c, 0x70, 0xe3, 0xcf, 0x9f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x70, 0xbf,
  0xcf, 0xe3, 0x70, 0x78, 0x3e, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x33, 0x77, 0x66, 0x66, 0x66, 0x6c,
  0x7d, 0x18, 0x00, 0x1f, 0x3f, 0x76, 0x66, 0x66, 0x66, 0x76, 0x37, 0x07, 0x00, 0x0f, 0x3f, 0x7f,
  0x66, 0x66, 0x66, 0x66, 0x77, 0x27, 0x07, 0x00, 0x1f, 0x3f, 0x76, 0x66, 0x66, 0x66, 0x76, 0x37,
  0x07, 0x00, 0x0f, 0x3f, 0x71, 0x60, 0x60, 0x60, 0x60, 0x31, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
  0x11, 0x37, 0x67, 0x66, 0x66, 0x6c, 0x7d, 0x38, 0x00, 0x00, 0x3f, 0x7f, 0x3f, 0x00, 0x00, 0x1f,
  0x3f, 0x70, 0x60, 0x60, 0x70, 0x7f, 0x7f, 0x00, 0x0f, 0x3f, 0x71, 0x60, 0x60, 0x60, 0x60, 0x31,
  0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x00, 0x06, 0x1f, 0x3b, 0x60, 0x60, 0x60, 0x60, 0x71, 0x3f, 0x1f,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x48, 0x48, 0x48, 0xb0, 0x00, 0xc0, 0x20,
  0x20, 0x20, 0xc0, 0x00, 0xc0, 0x20, 0x20, 0x20, 0xc0, 0x00, 0x40, 0xa0, 0xa0, 0xa0, 0x20, 0x00,
  0x00, 0x20, 0xf0, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0xf8, 0x08,
  0x08, 0x00, 0xc0, 0x20, 0x20, 0x20, 0xf8, 0x00, 0xc0, 0xa0, 0xa0, 0xa0, 0xc0, 0x00, 0x20, 0xa0,
  0xa0, 0xa0, 0xc0, 0x00, 0x40, 0xa0, 0xa0, 0xa0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x48, 0x48, 0x48, 0x08, 0x00, 0x20, 0x40, 0x80, 0x40,
  0x20, 0x00, 0x00, 0x20, 0xf0, 0x20, 0x20, 0x00, 0xc0, 0xa0, 0xa0, 0xa0, 0xc0, 0x00, 0xe0, 0x00,
  0x20, 0x20, 0xc0, 0x00, 0xc0, 0x20, 0x20, 0x20, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x02, 0x02, 0x01, 0x00, 0x01, 0x02,
  0x02, 0x02, 0x01, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00,
  0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x02,
  0x02, 0x00, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02,
  0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x02, 0x82, 0x02, 0x00, 0x02, 0x01, 0x01, 0x01,
  0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x00, 0x03, 0x00,
  0x00, 0x00, 0x03, 0x00, 0x01, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x82, 0x8c, 0x60, 0x1c, 0x02, 0x00, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x00, 0x1e,
  0x20, 0x20, 0x00, 0x3e, 0x00, 0x00, 0x3e, 0x04, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x3e, 0x04, 0x02, 0x02, 0x00, 0x1c, 0x2a, 0x2a, 0x2a, 0x0c, 0x00, 0x12, 0x2a, 0x2a,
  0x2a, 0x1c, 0x20, 0x1c, 0x22, 0x22, 0x22, 0x14, 0x00, 0x3f, 0x00, 0x02, 0x02, 0x3c, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

char addressingMode;


void init(void);

void setNormalDisplay();
void setInverseDisplay();

void sendCommand(unsigned char command);
void sendData(unsigned char Data);

void setPageMode();
void setHorizontalMode();

void setTextXY(unsigned char Row, unsigned char Column);
void clearDisplay();
void setBrightness(unsigned char Brightness);
void setTextSize(unsigned char Size);
void putChar(unsigned char c);
void putString(const char* String);
unsigned char putNumber(long n);
unsigned char putFloat(float floatNumber, unsigned char decimal);
unsigned char putFloat(float floatNumber);
void drawBitmap(unsigned char* bitmaparray, int bytes);

void setHorizontalScrollProperties(unsigned char direction, unsigned char startPage, unsigned char endPage,
    unsigned char scrollSpeed);
void activateScroll();
void deactivateScroll();

/*
   SeeedOLED.cpp
   SSD130x OLED Driver Library

   Copyright (c) 2011 seeed technology inc.
Author        :   Visweswara R
Create Time   :   Dec 2011
Change Log    :

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#define PROGMEM

// 8x8 Font ASCII 32 - 127 Implemented
// Users can modify this to support more characters(glyphs)
// BasicFont is placed in code memory.

// This font be freely used without any restriction(It is placed in public domain)
const unsigned char BasicFont[][8] PROGMEM = {
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00},
  {0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00, 0x00},
  {0x00, 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00, 0x00},
  {0x00, 0x23, 0x13, 0x08, 0x64, 0x62, 0x00, 0x00},
  {0x00, 0x36, 0x49, 0x55, 0x22, 0x50, 0x00, 0x00},
  {0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x1C, 0x22, 0x41, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x41, 0x22, 0x1C, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x08, 0x2A, 0x1C, 0x2A, 0x08, 0x00, 0x00},
  {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00, 0x00},
  {0x00, 0xA0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00},
  {0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 0x00},
  {0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x00},
  {0x00, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00, 0x00},
  {0x00, 0x62, 0x51, 0x49, 0x49, 0x46, 0x00, 0x00},
  {0x00, 0x22, 0x41, 0x49, 0x49, 0x36, 0x00, 0x00},
  {0x00, 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00, 0x00},
  {0x00, 0x27, 0x45, 0x45, 0x45, 0x39, 0x00, 0x00},
  {0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30, 0x00, 0x00},
  {0x00, 0x01, 0x71, 0x09, 0x05, 0x03, 0x00, 0x00},
  {0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00},
  {0x00, 0x06, 0x49, 0x49, 0x29, 0x1E, 0x00, 0x00},
  {0x00, 0x00, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0xAC, 0x6C, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x00},
  {0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00},
  {0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x00, 0x00},
  {0x00, 0x02, 0x01, 0x51, 0x09, 0x06, 0x00, 0x00},
  {0x00, 0x32, 0x49, 0x79, 0x41, 0x3E, 0x00, 0x00},
  {0x00, 0x7E, 0x09, 0x09, 0x09, 0x7E, 0x00, 0x00},
  {0x00, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00, 0x00},
  {0x00, 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00, 0x00},
  {0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C, 0x00, 0x00},
  {0x00, 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00, 0x00},
  {0x00, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00, 0x00},
  {0x00, 0x3E, 0x41, 0x41, 0x51, 0x72, 0x00, 0x00},
  {0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x00},
  {0x00, 0x41, 0x7F, 0x41, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00, 0x00},
  {0x00, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00},
  {0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00},
  {0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F, 0x00, 0x00},
  {0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00, 0x00},
  {0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00, 0x00},
  {0x00, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00, 0x00},
  {0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00, 0x00},
  {0x00, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00, 0x00},
  {0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x00},
  {0x00, 0x01, 0x01, 0x7F, 0x01, 0x01, 0x00, 0x00},
  {0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00, 0x00},
  {0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00, 0x00},
  {0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00, 0x00},
  {0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x00},
  {0x00, 0x03, 0x04, 0x78, 0x04, 0x03, 0x00, 0x00},
  {0x00, 0x61, 0x51, 0x49, 0x45, 0x43, 0x00, 0x00},
  {0x00, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00},
  {0x00, 0x41, 0x41, 0x7F, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x00},
  {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00},
  {0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x00},
  {0x00, 0x7F, 0x48, 0x44, 0x44, 0x38, 0x00, 0x00},
  {0x00, 0x38, 0x44, 0x44, 0x28, 0x00, 0x00, 0x00},
  {0x00, 0x38, 0x44, 0x44, 0x48, 0x7F, 0x00, 0x00},
  {0x00, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x00},
  {0x00, 0x08, 0x7E, 0x09, 0x02, 0x00, 0x00, 0x00},
  {0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C, 0x00, 0x00},
  {0x00, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x00},
  {0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x80, 0x84, 0x7D, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00},
  {0x00, 0x41, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x7C, 0x04, 0x18, 0x04, 0x78, 0x00, 0x00},
  {0x00, 0x7C, 0x08, 0x04, 0x7C, 0x00, 0x00, 0x00},
  {0x00, 0x38, 0x44, 0x44, 0x38, 0x00, 0x00, 0x00},
  {0x00, 0xFC, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00},
  {0x00, 0x18, 0x24, 0x24, 0xFC, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0x7C, 0x08, 0x04, 0x00, 0x00, 0x00},
  {0x00, 0x48, 0x54, 0x54, 0x24, 0x00, 0x00, 0x00},
  {0x00, 0x04, 0x7F, 0x44, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x3C, 0x40, 0x40, 0x7C, 0x00, 0x00, 0x00},
  {0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00, 0x00},
  {0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00, 0x00},
  {0x00, 0x44, 0x28, 0x10, 0x28, 0x44, 0x00, 0x00},
  {0x00, 0x1C, 0xA0, 0xA0, 0x7C, 0x00, 0x00, 0x00},
  {0x00, 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00, 0x00},
  {0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x41, 0x36, 0x08, 0x00, 0x00, 0x00, 0x00},
  {0x00, 0x02, 0x01, 0x01, 0x02, 0x01, 0x00, 0x00},
  {0x00, 0x02, 0x05, 0x05, 0x02, 0x00, 0x00, 0x00}
};

#define I2C_SD1306_ADDR      0x3c

static unsigned char textRow = 0, textColumn = 0, textSize = 1;
static unsigned char doubleBits[16]= {
  0x0, 0x3, 0xf, 0xf, 0x30,  0x33, 0x3c, 0x3f,  0xc0, 0xc3, 0xcc, 0xcf, 0xf0, 0xf3, 0xfc, 0xff};
void sendCommand(unsigned char command) {
  /*
     Wire.beginTransmission(SeeedOLED_Address); // begin I2C communication
#if defined(ARDUINO) && ARDUINO >= 100
Wire.write(SeeedOLED_Command_Mode);        // Set OLED Command mode
Wire.write(command);
#else
Wire.send(SeeedOLED_Command_Mode);         // Set OLED Command mode
Wire.send(command);
#endif
Wire.endTransmission();                // End I2C communication
*/
  i2c_start();
  i2c_tx((I2C_SD1306_ADDR<<1) | I2C_WR_FLAG);
  SDA_ON;
  i2c_delay();
  i2c_tx(SeeedOLED_Command_Mode);
  SDA_ON;
  i2c_delay();
  i2c_tx(command);
  i2c_stop();
}

#define SETCONTRAST          0x81
#define DISPLAYALLON_RESUME  0xA4
#define DISPLAYALLON         0xA5
#define NORMALDISPLAY        0xA6
#define INVERTDISPLAY        0xA7
#define DISPLAYOFF           0xAE
#define DISPLAYON            0xAF
#define SETDISPLAYOFFSET     0xD3
#define SETCOMPINS           0xDA
#define SETVCOMDETECT        0xDB
#define SETDISPLAYCLOCKDIV   0xD5
#define SETPRECHARGE         0xD9
#define SETMULTIPLEX         0xA8
#define SETLOWCOLUMN         0x00
#define SETHIGHCOLUMN        0x10
#define SETSTARTLINE         0x40
#define MEMORYMODE           0x20
#define COLUMNADDR           0x21
#define PAGEADDR             0x22
#define COMSCANINC           0xC0
#define COMSCANDEC           0xC8
#define SEGREMAP             0xA0
#define CHARGEPUMP           0x8D


void command(uint8_t reg, uint8_t val) {
  uint8_t data[3];

  data[0] = 0; data[1] = reg; data[2] = val;

  i2c_write_raw_u8(I2C_SD1306_ADDR, data, 3);
}
void command0(uint8_t val) {
  uint8_t data[2];
  data[0] = 0; data[1] = val;
  i2c_write_raw_u8(I2C_SD1306_ADDR, data, 2);
}

void init(void) {
  /*
     sendCommand(SeeedOLED_Display_Off_Cmd);     //display off
     delay(5);
     sendCommand(SeeedOLED_Display_On_Cmd);  //display on
     delay(5);
     sendCommand(SeeedOLED_Normal_Display_Cmd);  //Set Normal Display (default)
     */

  command0(DISPLAYOFF);
  command(SETDISPLAYCLOCKDIV, 0x80); // # the suggested ratio 0x80

  command(SETMULTIPLEX, 0x3f);

  command(SETDISPLAYOFFSET, 0);
  command0(SETSTARTLINE | 0x0);
  command(CHARGEPUMP, 0x14);
  command(MEMORYMODE, 0x02);
  command0(SEGREMAP | 0x1);
  command0(COMSCANDEC);

  command(SETCOMPINS, 0x12);
  command(SETCONTRAST, 0x7f);
  command(SETPRECHARGE, 0xf1);

  command(SETVCOMDETECT, 0x40);
  command0(DISPLAYALLON_RESUME);

  //command0(NORMALDISPLAY);
  command0(INVERTDISPLAY);
  command0(DISPLAYON);
}


void setBrightness(unsigned char Brightness) {
  sendCommand(SeeedOLED_Set_Brightness_Cmd);
  sendCommand(Brightness);
}

void setHorizontalMode() {
  addressingMode = HORIZONTAL_MODE;
  sendCommand(0x20);          //set addressing mode
  sendCommand(0x00);          //set horizontal addressing mode
}

void setPageMode() {
  addressingMode = PAGE_MODE;
  sendCommand(0x20);          //set addressing mode
  sendCommand(0x02);          //set page addressing mode
}


void setTextXY(unsigned char Row, unsigned char Column) {
  sendCommand(0xB0 + Row);            //set page address
  sendCommand(0x00 + (8 * Column & 0x0F)); //set column lower address
  sendCommand(0x10 + ((8 * Column >> 4) & 0x0F)); //set column higher address
}


void clearDisplay() {
  unsigned char i, j;
  sendCommand(SeeedOLED_Display_Off_Cmd);   //display off
  for (j = 0; j < 8; j++) {
    setTextXY(j, 0);
    {
      for (i = 0; i < 16; i++) { //clear all columns
        putChar(' ');
      }
    }
  }
  sendCommand(SeeedOLED_Display_On_Cmd);    //display on
  setTextXY(0, 0);
}

void sendData(unsigned char Data) {
  /*
     Wire.beginTransmission(SeeedOLED_Address); // begin I2C transmission
#if defined(ARDUINO) && ARDUINO >= 100
Wire.write(SeeedOLED_Data_Mode);            // data mode
Wire.write(Data);
#else
Wire.send(SeeedOLED_Data_Mode);            // data mode
Wire.send(Data);
#endif
Wire.endTransmission();                    // stop I2C transmission
*/
  i2c_start();
  i2c_tx((I2C_SD1306_ADDR<<1) | I2C_WR_FLAG);
  SDA_ON;
  i2c_delay();
  i2c_tx(SeeedOLED_Data_Mode);
  SDA_ON;
  i2c_delay();
  i2c_tx(Data);
  i2c_stop();
}

void setTextSize(unsigned char Size) {
  if(Size < 1)
    textSize = 1;
  else if (Size > 2)
    textSize = 2;
  else
    textSize = Size;
}

void putChar(unsigned char C) {
  if (C < 32 || C > 127) { //Ignore non-printable ASCII characters. This can be modified for multilingual font.
    C = ' '; //Space
  }
  if(textSize == 1) {
    unsigned char i = 0;
    for (i = 0; i < 8; i++) {
      //read bytes from code memory
      sendData(BasicFont[C - 32][i]); //font array starts at 0, ASCII starts at 32. Hence the translation
    }
    textColumn++;
  } else if (textSize == 2) {
    unsigned char currentRow = textRow;
    unsigned char i, bits;

    // draw the upper half 
    for (i = 0; i < 8; i++) {
      bits = doubleBits[(BasicFont[C - 32][i]) & 0xf];
      sendData(bits);
      sendData(bits);
    }
    // draw the lower half 
    setTextXY(textRow+1, textColumn);
    for (i = 0; i < 8; i++) {
      bits = doubleBits[((BasicFont[C - 32][i]) >> 4) & 0xf];
      sendData(bits);
      sendData(bits);
    }
    setTextXY(currentRow, textColumn+2);
  }
}

void putString(const char* String) {
  unsigned char i = 0;
  while (String[i]) {
    putChar(String[i]);
    i++;
  }
}

unsigned char putNumber(long long_num) {
  unsigned char char_buffer[10] = "";
  unsigned char i = 0;
  unsigned char f = 0;

  if (long_num < 0) {
    f = 1;
    putChar('-');
    long_num = -long_num;
  } else if (long_num == 0) {
    f = 1;
    putChar('0');
    return f;
  }

  while (long_num > 0) {
    char_buffer[i++] = long_num % 10;
    long_num /= 10;
  }

  f = f + i;
  for (; i > 0; i--) {
    putChar('0' + char_buffer[i - 1]);
  }
  return f;

}

unsigned char putFloat(float floatNumber, unsigned char decimal) {
  unsigned int temp = 0;
  float decy = 0.0;
  float rounding = 0.5;
  unsigned char f = 0;
  if (floatNumber < 0.0) {
    putString("-");
    floatNumber = -floatNumber;
    f += 1;
  }
  for (unsigned char i = 0; i < decimal; ++i) {
    rounding /= 10.0;
  }
  floatNumber += rounding;

  temp = floatNumber;
  f += putNumber(temp);
  if (decimal > 0) {
    putChar('.');
    f += 1;
  }
  decy = floatNumber - temp; //decimal part,
  for (unsigned char i = 0; i < decimal; i++) { //4
    decy *= 10; // for the next decimal
    temp = decy;//get the decimal
    putNumber(temp);
    decy -= temp;
  }
  f += decimal;
  return f;
}
unsigned char putFloat(float floatNumber) {
  unsigned char decimal = 2;
  unsigned int temp = 0;
  float decy = 0.0;
  float rounding = 0.5;
  unsigned char f = 0;
  if (floatNumber < 0.0) {
    putString("-");
    floatNumber = -floatNumber;
    f += 1;
  }
  for (unsigned char i = 0; i < decimal; ++i) {
    rounding /= 10.0;
  }
  floatNumber += rounding;

  temp = floatNumber;
  f += putNumber(temp);
  if (decimal > 0) {
    putChar('.');
    f += 1;
  }
  decy = floatNumber - temp; //decimal part,
  for (unsigned char i = 0; i < decimal; i++) { //4
    decy *= 10; // for the next decimal
    temp = decy;//get the decimal
    putNumber(temp);
    decy -= temp;
  }
  f += decimal;
  return f;
}

void drawBitmap(unsigned char* bitmaparray, int bytes) {
  char localAddressMode = addressingMode;
  if (addressingMode != HORIZONTAL_MODE) {
    //Bitmap is drawn in horizontal mode
    setHorizontalMode();
  }

  for (int i = 0; i < bytes; i++) {
    sendData(bitmaparray[i]);
  }

  if (localAddressMode == PAGE_MODE) {
    //If pageMode was used earlier, restore it.
    setPageMode();
  }

}

void setHorizontalScrollProperties(unsigned char direction, unsigned char startPage, unsigned char endPage,
    unsigned char scrollSpeed) {
  /*
     Use the following defines for 'direction' :

     Scroll_Left
     Scroll_Right

     Use the following defines for 'scrollSpeed' :

     Scroll_2Frames
     Scroll_3Frames
     Scroll_4Frames
     Scroll_5Frames
     Scroll_25Frames
     Scroll_64Frames
     Scroll_128Frames
     Scroll_256Frames

*/

  if (Scroll_Right == direction) {
    //Scroll Right
    sendCommand(0x26);
  } else {
    //Scroll Left
    sendCommand(0x27);

  }
  sendCommand(0x00);
  sendCommand(startPage);
  sendCommand(scrollSpeed);
  sendCommand(endPage);
  sendCommand(0x00);
  sendCommand(0xFF);
}

void activateScroll() {
  sendCommand(SeeedOLED_Activate_Scroll_Cmd);
}

void deactivateScroll() {
  sendCommand(SeeedOLED_Dectivate_Scroll_Cmd);
}

void setNormalDisplay() {
  sendCommand(SeeedOLED_Normal_Display_Cmd);
}

void setInverseDisplay() {
  sendCommand(SeeedOLED_Inverse_Display_Cmd);
}

void setDisplayToOriginalState(char testCase)

{
  delay(5000);
  init();                       //initialze SEEED OLED display
  clearDisplay();               // clear the screen and set start position to top left corner
  deactivateScroll();           // deactivete Scroll (might be activated by previous test case)
  setNormalDisplay();           // Non-inverted Display
  setPageMode();                // Page mode to start with
  setTextXY(2, 0);              // 0 Page, 0th Column
  putString("Test Case ");
  putNumber(testCase);
  setTextXY(3, 0);
  putString("Test Case ");
  putNumber(testCase);
  setTextXY(4, 0);
  putString("Test Case ");
  putNumber(testCase);
  setTextXY(5, 0);
  putString("Test Case ");
  putNumber(testCase);
  delay(2000);



}

void main() {
  init();  //initialze SEEED OLED display
  for (;;) { 

    clearDisplay();          //clear the screen and set start position to top left corner
    setNormalDisplay();      //Set display to normal mode (i.e non-inverse mode)
    setPageMode();           //Set addressing mode to Page Mode
    setTextXY(0, 0);         //Set the cursor to Xth Page, Yth Column
    putString("==============="); //Print the String
    setTextXY(1, 0);         //Set the cursor to Xth Page, Yth Column
    putString("KianRiscv"); //Print the String
    setTextXY(2, 0);         //Set the cursor to Xth Page, Yth Column
    putString("rv32im"); //Print the String
    setTextXY(3, 0);         //Set the cursor to Xth Page, Yth Column
    putString("bitbang i2c"); //Print the String
    setTextXY(4, 0);         //Set the cursor to Xth Page, Yth Column
    putString("oled sd1306"); //Print the String
    setTextXY(4, 0);         //Set the cursor to Xth Page, Yth Column
    putString("==============="); //Print the String

    sleep(3);

    setDisplayToOriginalState(1);

    clearDisplay();          //clear the screen and set start position to top left corner
    setNormalDisplay();      //Set display to normal mode (i.e non-inverse mode)
    setPageMode();           //Set addressing mode to Page Mode
    setTextXY(0, 0);         //Set the cursor to Xth Page, Yth Column
    putString("Hello World!"); //Print the String


    setDisplayToOriginalState(2);

    clearDisplay();           //clear the screen and set start position to top left corner
    setNormalDisplay();       //Set display to Normal mode
    setPageMode();            //Set addressing mode to Page Mode
    setTextXY(0, 0);          //Set the cursor to 0th Page, 0th Column
    putNumber(123);           //Print number
    setTextXY(1, 0);          //Set the cursor to 1st Page, 0th Column
    putNumber(0xFFFF);        //Print number
    setTextXY(2, 0);          //Set the cursor to 2nd Page, 0th Column
    putNumber(0xFFFFFFFF);    //Print number
    setTextXY(3, 0);          //Set the cursor to 3rd Page, 0th Column
    putNumber(-12345);        //Print number


    setDisplayToOriginalState(3);

    clearDisplay();           //clear the screen and set start position to top left corner
    setNormalDisplay();       //Set display to Normal mode
    setHorizontalMode();      //Set addressing mode to Horizontal Mode
    putString("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");  //Print String (ASCII 32 - 126 )



    setDisplayToOriginalState(4);

    clearDisplay();               // clear the screen and set start position to top left corner
    drawBitmap((unsigned char*) SeeedLogo, 1024);  // 1024 = 128 Pixels * 64 Pixels / 8

    setDisplayToOriginalState(5);

    setInverseDisplay();          // Set Display to inverse mode
    clearDisplay();               // clear the screen and set start position to top left corner
    drawBitmap((unsigned char*) SeeedLogo, 1024);  // 1024 = 128 Pixels * 64 Pixels / 8

    setDisplayToOriginalState(6);

    clearDisplay();               // clear the screen and set start position to top left corner
    drawBitmap((unsigned char*) SeeedLogo, 1024);  // 1024 = 128 Pixels * 64 Pixels / 8
    setHorizontalScrollProperties(Scroll_Left, 3, 6, Scroll_5Frames); //Set Scrolling properties to Scroll Left
    activateScroll();             // Activate Scrolling
    usleep(5000);

    setDisplayToOriginalState(7);

    clearDisplay();               // clear the screen and set start position to top left corner
    drawBitmap((unsigned char*) SeeedLogo, 1024);  // 1024 = 128 Pixels * 64 Pixels / 8
    setHorizontalScrollProperties(Scroll_Right, 3, 6, Scroll_5Frames); //Set the properties of Horizontal Scrool
    activateScroll();             // Activate Scroll
    usleep(5000);
  }

}

